/*
 * Copyright 2013-2018 Lilinfeng.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.doeis.baseHandler;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

import java.io.IOException;

import org.apache.log4j.Logger;

import com.doeis.common.utils.StringUtils;
import com.doeis.minaserver.SystemProperties;
import com.doeis.minaserver.handler.IdlChannelHandlerAdapter;
import com.doeis.minaserver.packet.NettyMessageDecoder;
import com.doeis.minaserver.packet.NettyMessageEncoder;
import com.doeis.minaserver.packet.Packet;
import com.doeis.uwork.common.Constant;
import com.doeis.uwork.entity.mongo.MethodLog;
import com.voland.core.db.Entity;
import com.voland.core.utils.IDGenerator;

/**
 * 这个方法测试编码是否导致接受包的时候慢
 * @author tianbx                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
 * @date 2014年2月14日
 * @version 1.0
 */
public class HandlerServer {

    public void bind(int port) throws Exception {
	// 配置服务端的NIO线程组
	EventLoopGroup bossGroup = new NioEventLoopGroup();
	EventLoopGroup workerGroup = new NioEventLoopGroup();
	try {
	    ServerBootstrap b = new ServerBootstrap();
	    b.group(bossGroup, workerGroup)
		    .channel(NioServerSocketChannel.class)
		    .option(ChannelOption.SO_BACKLOG, 1024)
		    .childHandler(new ChildChannelHandler());
	    // 绑定端口，同步等待成功
	    ChannelFuture f = b.bind(port).sync();

	    // 等待服务端监听端口关闭
	    f.channel().closeFuture().sync();
	} finally {
	    // 优雅退出，释放线程池资源
	    bossGroup.shutdownGracefully();
	    workerGroup.shutdownGracefully();
	}
    }
    
    private static final int MAX_IDLE_TIME = 5 * 60; // 单位是秒

    private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
	@Override
	protected void initChannel(SocketChannel socketChannel) throws Exception {
		socketChannel.pipeline().addLast(new NettyMessageDecoder());
		socketChannel.pipeline().addLast(new NettyMessageEncoder());
		socketChannel.pipeline().addLast("IdleStateHandler",
				new IdleStateHandler( MAX_IDLE_TIME,  MAX_IDLE_TIME,  MAX_IDLE_TIME ));
		socketChannel.pipeline().addLast("IdlChannelHandlerAdapter",
				new IdlChannelHandlerAdapter());
		socketChannel.pipeline().addLast(new NettyChannelHandlerAdapter());
	}

    }
    
    
    class NettyChannelHandlerAdapter extends ChannelHandlerAdapter {
		
		private final Logger log = Logger.getLogger(NettyChannelHandlerAdapter.class);
		
		@Override
		public void channelRead(ChannelHandlerContext ctx, Object msg)
				throws Exception {
			if(SystemProperties.isLogError()){
				log.error( " ctx.channel().id(): " + ctx.channel().id().toString() + " >>> "+msg.toString());
			}
			
			
			Packet packet = (Packet)msg;
			String from = packet.getFrom();
			String to = packet.getTo();
			
			//进行日志发送
//			sendLog(packet, false,  ctx.channel().id().toString() );
			MethodLog methodLog = new MethodLog();
			methodLog.setCreateTime(com.voland.core.utils.DateUtils.currentDateTime());
			methodLog.setId(IDGenerator.uuid());
			methodLog.setMethod("channelRead");
			methodLog.setNote(packet.getCmd()+"收到包消息");
			methodLog.setUser_id(from);
			methodLog.setFirstTime(methodLog.getCreateTime());
			sendLog(methodLog);
			
			packet.setFirstTime(methodLog.getCreateTime());
			
			if( StringUtils.isBlank(from) || StringUtils.isBlank(to) ){
				throw new NullPointerException("From or to with null value!");
			}
			if( !from.equals(to) ){	
				//这里把业务数据上传到用户层，用户来处理实际业务
//				packetHandler.process(packet, clienConn);
			}
		}

		
		@Override
		public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
			if(SystemProperties.isLogError()){
				log.error( " ctx.channel().id(): " + ctx.channel().id().toString());
			}
			super.channelRegistered(ctx);
			
			
			sendLog(ctx, Constant.SESSION_STATUS_OPEN);
			
		}

		@Override
		public void channelInactive(ChannelHandlerContext ctx) throws Exception {
			if(SystemProperties.isLogError()){
				log.error( " ctx.channel().id(): " + ctx.channel().id().toString());
			}
			super.channelInactive(ctx);
			sendLog(ctx, Constant.SESSION_STATUS_CLOSE);
			closeClientConnection(ctx);
		}

		@Override
		public void close(ChannelHandlerContext ctx, ChannelPromise promise)
				throws Exception {
			super.close(ctx, promise);
			closeClientConnection(ctx);
		}

		@Override
		public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
			log.error( " ctx.channel().id(): " + ctx.channel().id().toString());
			
			
			String msg = cause.getMessage();		
			if (cause instanceof IOException) {
//				log.error(msg, cause);
			}else {
				log.error(msg, cause);
			}	
			ctx.close();
		}
		
		
		/**
		 * 任何连接被关闭的情况都会调用本方法
		 * @param ioSession
		 */
		private void closeClientConnection(ChannelHandlerContext ctx) {
		}
		
		private void sendLog(Packet packet, boolean send, String sessionid){
			try{
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		
		
		private void sendLog(Entity entity){
			try{
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		
		private void sendLog(ChannelHandlerContext session, int status){
		}
		
	}

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
	int port = 9999;
	if (args != null && args.length > 0) {
	    try {
		port = Integer.valueOf(args[0]);
	    } catch (NumberFormatException e) {
		// 采用默认值
	    }
	}
	new HandlerServer().bind(port);
    }
}
